home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / schmlbrr / schem_lb.lha / unsupported / MacScheme / extend.sch
Encoding:
Internet Message Format  |  1993-07-16  |  14.1 KB

  1. From jdevries@zodiac.ads.com Tue Nov 24 17:41:59 1987
  2. To: 
  3. Path: xanth!mcnc!gatech!hao!ames!ucbcad!zodiac!jdevries
  4. From: jdevries@zodiac.ads.com (Jeff De Vries)
  5. Newsgroups: comp.lang.lisp,mail.scheme
  6. Subject: Extend-Syntax for Everybody!
  7. Date: 13 Nov 87 21:44:20 GMT
  8. Sender: zodiac!news
  9. Reply-To: jdevries@ADS.ARPA (Jeff De Vries)
  10. Distribution: world
  11. Organization: Advanced Decision Systems, Mt. View, CA (415) 941-3912
  12. Lines: 377
  13.  
  14.  
  15.  
  16. By popular demand I have decided to go ahead and post the code for the
  17. MacScheme version of extend-syntax.  I had (have?) over 40 requests,
  18. (some of which I can't seem to respond to due to always getting bounced),
  19. plus other indicators that some people are just waiting for me to post it.
  20. To those of you who have no interest in this, I apologize for the long
  21. posting, (just hit your 'junk' key, if you have one).  
  22.  
  23. But first, a few words:
  24.  
  25. The theoretical work and basic design behind extend-syntax was the work of 
  26. Eugene Kohlbecker.  It was part of his Ph.D. dissertation, "Syntactic 
  27. Extensions in the Programming Language LISP", (Indiana University, 1986).  
  28. The enhanced version of the code that I used for the MacScheme version was 
  29. written by R. Kent Dybvig, and made available by him.
  30.  
  31. A more complete description of Kent's book is:
  32.     The Scheme Programming Language
  33.     R. Kent Dybvig
  34.     Prentice-Hall, Englewood Cliffs, New Jersey, 07632 (1987)
  35.     Library of Congress Catalog Card Number 86-63489
  36.  
  37. If you are using a version of Scheme other than MacScheme, you should be
  38. able to convert this to whatever you are using.  The main thing to change
  39. is the way macros are defined.  There are two macros, (extend-syntax and
  40. extend-syntax/code), plus the macro defining form embedded inside of
  41. extend-syntax.  You may have to add (or delete) a support function or two.
  42.  
  43. ENJOY!!! :-)
  44.  
  45. Jeff
  46.  
  47. ------------------------distribution starts here------------------------
  48. Here is the code for extend-syntax.  It includes the code for:
  49.     when
  50.     unless
  51.     andmap
  52.     syntax-match?
  53.     extend-syntax
  54.     extend-syntax/code
  55.  
  56. To load it, just enter
  57.  (load "extend.sch")
  58.  
  59. It takes a while to load and will print out:
  60.     when
  61.     unless
  62.     andmap
  63.     syntax-match?
  64.     extend-syntax/code
  65. (note: extend-syntax gets compiled even though its name doesn't get
  66.     printed.  It doesn't get printed because it's inside the LET)
  67.  
  68. After you load it, you may want to do a (dumpheap)  See the MacScheme
  69. manual for details.
  70.  
  71. The documentation for extend-syntax is in "The Scheme Programming
  72. Language" by R. Kent Dybvig.  Buy the book.  (No, I don't get any
  73. kickbacks).  extend-syntax/code returns the source for the
  74. lambda expression that would have been bound to the macro, which is
  75. helpful during debugging and for getting a feel for how extend-syntax
  76. works.  You might try (pretty-print (extend-syntax/code --- etc. if
  77. you want to be able to read it easily.  Note that the output isn't
  78. directly useable because of gensym'ed variables and how MacScheme
  79. prints quasiquotes, etc.  Use extend-syntax to make the macros.
  80.  
  81. If you have any comments or problems, feel free to contact me.  I won't
  82. promise anything, but I'll give it a look.  If you port the code to another
  83. version of Scheme, I would be interested in hearing about it.
  84.  
  85. Jeff De Vries
  86. (ARPA: jdevries@ads.arpa)
  87. DISCLAIMER: All the usual stuff...
  88.  
  89. -----------------------------snip here---------------------------------
  90. ;;; extend.sch
  91. ;;; Copyright (C) 1987 Cadence Research Systems
  92. ;;; Permission to copy this software, in whole or in part, to use this
  93. ;;; software for any lawful noncommercial purpose, and to redistribute
  94. ;;; this software is granted subject to the restriction that all copies
  95. ;;; made of this software must include this copyright notice in full.
  96. ;;; Cadence makes no warranties or representations of any kind, either
  97. ;;; express or implied, including but not limited to implied warranties
  98. ;;; of merchantability or fitness for any particular purpose.
  99.  
  100. ;;; The basic design of extend-syntax is due to Eugene Kohlbecker.  See
  101. ;;; "E. Kohlbecker: Syntactic Extensions in the Programming Language Lisp",
  102. ;;; Ph.D.  Dissertation, Indiana University, 1986."  The structure of "with"
  103. ;;; pattern/value clauses, the method for compiling extend-syntax into
  104. ;;; Scheme code, and the actual implementation are due to Kent Dybvig.
  105.  
  106. ;;; Made available courtesy R. Kent Dybvig
  107. ;;; MacScheme conversion by Jeff De Vries
  108. ;;; note: requires the use of MacScheme Version 1.2 or greater
  109.  
  110. ;;; the following routines are provided for compatibility with TSPL:
  111. (macro when
  112.        (lambda (args)
  113.          `(if ,(cadr args)
  114.               (begin ,@(cddr args))
  115.               #f)))
  116. (macro unless
  117.        (lambda (args)
  118.          `(if ,(cadr args)
  119.               #t
  120.               (begin ,@(cddr args)))))
  121.  
  122. (define (andmap p . args)
  123.    ;; use "first-finish" rule
  124.    (let andmap ((args args) (value #t))
  125.       (if (let any-at-end? ((ls args))
  126.              (and (pair? ls)
  127.                   (or (not (pair? (car ls)))
  128.                       (any-at-end? (cdr ls)))))
  129.           value
  130.           (let ((value (apply p (map car args))))
  131.              (and value (andmap (map cdr args) value))))))
  132.  
  133. ;;; syntax-match? is used by extend-syntax to choose among clauses and
  134. ;;; to check for syntactic errors.  It is also available to the user.
  135. (define syntax-match?
  136.    (lambda (keys pat exp)
  137.       (cond
  138.          ((symbol? pat) (if (memq pat keys) (eq? exp pat) #t))
  139.          ((pair? pat)
  140.           (if (equal? (cdr pat) '(...))
  141.               (let f ((lst exp))
  142.                  (or (null? lst)
  143.                      (and (pair? lst)
  144.                           (syntax-match? keys (car pat) (car lst))
  145.                           (f (cdr lst)))))
  146.               (and (pair? exp)
  147.                    (syntax-match? keys (car pat) (car exp))
  148.                    (syntax-match? keys (cdr pat) (cdr exp)))))
  149.          (else (equal? exp pat)))))
  150.  
  151. ;;; The main code!
  152. (let ()
  153.    (define id
  154.       (lambda (name access control)
  155.          (list name access control)))
  156.    (define id-name car)
  157.    (define id-access cadr)
  158.    (define id-control caddr)
  159.  
  160.    (define loop
  161.       (lambda ()
  162.          (list '())))
  163.    (define loop-ids car)
  164.    (define loop-ids! set-car!)
  165.  
  166.    (define c...rs
  167.       `((car caar . cdar)
  168.         (cdr cadr . cddr)
  169.         (caar caaar . cdaar)
  170.         (cadr caadr . cdadr)
  171.         (cdar cadar . cddar)
  172.         (cddr caddr . cdddr)
  173.         (caaar caaaar . cdaaar)
  174.         (caadr caaadr . cdaadr)
  175.         (cadar caadar . cdadar)
  176.         (caddr caaddr . cdaddr)
  177.         (cdaar cadaar . cddaar)
  178.         (cdadr cadadr . cddadr)
  179.         (cddar caddar . cdddar)
  180.         (cdddr cadddr . cddddr)))
  181.  
  182.    (define add-car
  183.       (lambda (access)
  184.          (let ((x (and (pair? access) (assq (car access) c...rs))))
  185.             (if (null? x)
  186.                 `(car ,access)
  187.                 `(,(cadr x) ,@(cdr access))))))
  188.  
  189.    (define add-cdr
  190.       (lambda (access)
  191.          (let ((x (and (pair? access) (assq (car access) c...rs))))
  192.             (if (null? x)
  193.                 `(cdr ,access)
  194.                 `(,(cddr x) ,@(cdr access))))))
  195.  
  196.    (define parse
  197.       (lambda (keys pat acc cntl ids)
  198.          (cond
  199.             ((symbol? pat)
  200.              (if (memq pat keys)
  201.                  ids
  202.                  (cons (id pat acc cntl) ids)))
  203.             ((pair? pat)
  204.              (if (equal? (cdr pat) '(...))
  205.                  (let ((x (gensym)))
  206.                     (parse keys (car pat) x (id x acc cntl) ids))
  207.                  (parse keys (car pat) (add-car acc) cntl
  208.                     (parse keys (cdr pat) (add-cdr acc) cntl ids))))
  209.             (else ids))))
  210.  
  211.    (define gen
  212.       (lambda (keys exp ids loops)
  213.          (cond
  214.             ((symbol? exp)
  215.              (let ((id (lookup exp ids)))
  216.                 (if (null? id)
  217.                     exp
  218.                     (begin
  219.                        (add-control! (id-control id) loops)
  220.                        (list 'unquote (id-access id))))))
  221.             ((pair? exp)
  222.              (cond
  223.                 ((eq? (car exp) 'with)
  224.                  (unless (syntax-match? '(with) '(with ((p x) ...) e) exp)
  225.                     (error 'extend-syntax "invalid 'with' form" exp))
  226.                  (list 'unquote
  227.                     (gen-with
  228.                        keys
  229.                        (map car (cadr exp))
  230.                        (map cadr (cadr exp))
  231.                        (caddr exp)
  232.                        ids
  233.                        loops)))
  234.                 ((and (pair? (cdr exp)) (eq? (cadr exp) '...))
  235.                  (let ((x (loop)))
  236.                     (make-loop
  237.                        x
  238.                        (gen keys (car exp) ids (cons x loops))
  239.                        (gen keys (cddr exp) ids loops))))
  240.                 (else
  241.                  (let ((a (gen keys (car exp) ids loops))
  242.                        (d (gen keys (cdr exp) ids loops)))
  243.                     (if (and (pair? d) (eq? (car d) 'unquote))
  244.                         (list a (list 'unquote-splicing (cadr d)))
  245.                         (cons a d))))))
  246.             (else exp))))
  247.  
  248.    (define gen-with
  249.       (lambda (keys pats exps body ids loops)
  250.          (if (null? pats)
  251.              (make-quasi (gen keys body ids loops))
  252.              (let ((p (car pats)) (e (car exps)) (g (gensym)))
  253.                 `(let ((,g ,(gen-quotes keys e ids loops)))
  254.                     (if (syntax-match? '() ',p ,g)
  255.                         ,(gen-with
  256.                             keys
  257.                             (cdr pats)
  258.                             (cdr exps)
  259.                             body
  260.                             (parse '() p g '() ids)
  261.                             loops)
  262.                         (error ',(car keys)
  263.                                "does not fit 'with' pattern"
  264.                                ,g
  265.                                ',p)))))))
  266.  
  267.    (define gen-quotes
  268.       (lambda (keys exp ids loops)
  269.          (cond
  270.             ((syntax-match? '(quote) '(quote x) exp)
  271.              (make-quasi (gen keys (cadr exp) ids loops)))
  272.             ((pair? exp)
  273.              (cons (gen-quotes keys (car exp) ids loops)
  274.                    (gen-quotes keys (cdr exp) ids loops)))
  275.             (else exp))))
  276.  
  277.    (define lookup
  278.       (lambda (sym ids)
  279.          (let loop ((ls ids))
  280.             (cond
  281.                ((null? ls) #f)
  282.                ((eq? (id-name (car ls)) sym) (car ls))
  283.                (else (loop (cdr ls)))))))
  284.  
  285.    (define add-control!
  286.       (lambda (id loops)
  287.          (unless (null? id)
  288.             (when (null? loops)
  289.                (error 'extend-syntax "missing ellipsis in expansion"))
  290.             (let ((x (loop-ids (car loops))))
  291.                (unless (memq id x)
  292.                   (loop-ids! (car loops) (cons id x))))
  293.             (add-control! (id-control id) (cdr loops)))))
  294.  
  295.    (define make-loop
  296.       (lambda (loop body tail)
  297.          (let ((ids (loop-ids loop)))
  298.             (when (null? ids)
  299.                (error 'extend-syntax "extra ellipsis in expansion"))
  300.             (cond
  301.                ((equal? body (list 'unquote (id-name (car ids))))
  302.                 (if (null? tail)
  303.                     (list 'unquote (id-access (car ids)))
  304.                     (cons (list 'unquote-splicing (id-access (car ids)))
  305.                           tail)))
  306.                ((and (null? (cdr ids))
  307.                      (syntax-match? '(unquote) '(unquote (f x)) body)
  308.                      (eq? (cadadr body) (id-name (car ids))))
  309.                 (let ((x `(map ,(caadr body) ,(id-access (car ids)))))
  310.                    (if (null? tail)
  311.                        (list 'unquote x)
  312.                        (cons (list 'unquote-splicing x) tail))))
  313.                (else
  314.                 (let ((x `(map (lambda ,(map id-name ids) ,(make-quasi body))
  315.                                ,@(map id-access ids))))
  316.                    (if (null? tail)
  317.                        (list 'unquote x)
  318.                        (cons (list 'unquote-splicing x) tail))))))))
  319.  
  320.    (define make-quasi
  321.       (lambda (exp)
  322.          (if (and (pair? exp) (eq? (car exp) 'unquote))
  323.              (cadr exp)
  324.              (list 'quasiquote exp))))
  325.  
  326.    (define make-clause
  327.       (lambda (keys cl x)
  328.          (cond
  329.             ((syntax-match? '() '(pat fender exp) cl)
  330.              (let ((pat (car cl)) (fender (cadr cl)) (exp (caddr cl)))
  331.                 (let ((ids (parse keys pat x '() '())))
  332.                    `((and (syntax-match? ',keys ',pat ,x)
  333.                           ,(gen-quotes keys fender ids '()))
  334.                      ,(make-quasi (gen keys exp ids '()))))))
  335.             ((syntax-match? '() '(pat exp) cl)
  336.              (let ((pat (car cl)) (exp (cadr cl)))
  337.                 (let ((ids (parse keys pat x '() '())))
  338.                    `((syntax-match? ',keys ',pat ,x)
  339.                      ,(make-quasi (gen keys exp ids '()))))))
  340.             (else
  341.              (error 'extend-syntax "invalid clause" cl)))))
  342.  
  343.      (define make-syntax
  344.       (let ((x (gensym "x")))
  345.          (lambda (keys clauses)
  346.             `(lambda (,x)
  347.                 (cond
  348.                   ,@(map (lambda (cl) (make-clause keys cl x)) clauses)
  349.                   (else
  350.                    (error ',(car keys) "invalid syntax" ,x)))))))
  351.  
  352.      (macro extend-syntax
  353.           (lambda (x)
  354.             (cond
  355.               ((and
  356.                  (syntax-match?
  357.                   '(extend-syntax)
  358.                   '(extend-syntax (key1 key2 ...) clause ...)
  359.                   x)
  360.                  (andmap symbol? `(,(caadr x) ,@(cdadr x))))
  361.                (let
  362.                 ((f (make-syntax `(,(caadr x) ,@(cdadr x)) (cddr x))))
  363.                 (if (syntax-match? '() 'proc f)
  364.                  `(macro ,(caadr x) ,f)
  365.                   (error 'extend-syntax
  366.                          "does not fit 'with' pattern"
  367.                          f
  368.                          'proc))))
  369.               (else (error 'extend-syntax "invalid syntax" x)))))
  370.  
  371.        (macro extend-syntax/code
  372.           (lambda (x)
  373.             (cond
  374.               ((and
  375.                  (syntax-match?
  376.                   '(extend-syntax/code)
  377.                   '(extend-syntax/code (key1 key2 ...) clause ...)
  378.                   x)
  379.                  (andmap symbol? `(,(caadr x) ,@(cdadr x))))
  380.                (let
  381.                 ((f (make-syntax `(,(caadr x) ,@(cdadr x)) (cddr x))))
  382.                 (if (syntax-match? '() 'proc f)
  383.                  `',f
  384.                   (error 'extend-syntax/code
  385.                          "does not fit 'with' pattern"
  386.                          f
  387.                          'proc))))
  388.               (else (error 'extend-syntax/code "invalid syntax" x)))))
  389.   
  390. ) ;;; end of let
  391. ;;; end extend.sch
  392.  
  393.  
  394.  
  395.